package loger

import (
	"fmt"
	"os"
	"path/filepath"
	"sync"
	"time"
)

const (
	// 默认日志保留天数
	defaultRetentionDays = 30
	// 默认日志文件权限
	defaultFileMode = 0644
	// 默认目录权限
	defaultDirMode = 0755
)

// Logger 日志记录器
type Logger struct {
	// 基础目录路径
	baseDir string
	// 服务模块名称
	module string
	// 日志文件句柄
	file *os.File
	// 当前日志文件日期
	currentDate string
	// 日志保留天数
	retentionDays int
	// 互斥锁
	mu sync.Mutex
	// 是否已初始化
	initialized bool
}

// NewLogger 创建新的日志记录器
func NewLogger(baseDir, module string, retentionDays int) *Logger {
	if retentionDays <= 0 {
		retentionDays = defaultRetentionDays
	}

	return &Logger{
		baseDir:       baseDir,
		module:        module,
		retentionDays: retentionDays,
	}
}

// init 初始化日志记录器
func (l *Logger) init() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	if l.initialized {
		return nil
	}

	// 创建日志目录
	logDir := filepath.Join(l.baseDir, "logs", l.module)
	if err := os.MkdirAll(logDir, defaultDirMode); err != nil {
		return fmt.Errorf("创建日志目录失败: %v", err)
	}

	// 清理过期日志
	if err := l.cleanOldLogs(); err != nil {
		return fmt.Errorf("清理过期日志失败: %v", err)
	}

	l.initialized = true
	return nil
}

// getLogFile 获取当前日志文件
func (l *Logger) getLogFile() (*os.File, error) {
	currentDate := time.Now().Format("20060102")

	// 如果日期变化或文件未打开，需要切换文件
	if l.file == nil || l.currentDate != currentDate {
		// 关闭旧文件
		if l.file != nil {
			l.file.Close()
			l.file = nil
		}

		// 打开新文件
		logPath := filepath.Join(l.baseDir, "logs", l.module, currentDate+".log")
		file, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, defaultFileMode)
		if err != nil {
			return nil, fmt.Errorf("打开日志文件失败: %v", err)
		}

		l.file = file
		l.currentDate = currentDate
	}

	return l.file, nil
}

// cleanOldLogs 清理过期日志文件
func (l *Logger) cleanOldLogs() error {
	logDir := filepath.Join(l.baseDir, "logs", l.module)
	cutoffDate := time.Now().AddDate(0, 0, -l.retentionDays)

	entries, err := os.ReadDir(logDir)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return fmt.Errorf("读取日志目录失败: %v", err)
	}

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}

		// 解析文件名中的日期
		name := entry.Name()
		if len(name) < 12 { // "YYYYMMDD.log"
			continue
		}

		dateStr := name[:8]
		fileDate, err := time.ParseInLocation("20060102", dateStr, time.Local)
		if err != nil {
			continue
		}

		// 删除过期日志
		if fileDate.Before(cutoffDate) {
			filePath := filepath.Join(logDir, name)
			if err := os.Remove(filePath); err != nil {
				return fmt.Errorf("删除过期日志失败 [%s]: %v", name, err)
			}
		}
	}

	return nil
}

// Log 记录日志
func (l *Logger) Log(message string) error {
	if err := l.init(); err != nil {
		return err
	}

	l.mu.Lock()
	defer l.mu.Unlock()

	file, err := l.getLogFile()
	if err != nil {
		return err
	}

	timestamp := time.Now().Format("2006-01-02 15:04:05")
	logLine := fmt.Sprintf("[%s] %s\n", timestamp, message)

	_, err = file.WriteString(logLine)
	if err != nil {
		return fmt.Errorf("写入日志失败: %v", err)
	}

	return nil
}

// Close 关闭日志记录器
func (l *Logger) Close() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	if l.file != nil {
		err := l.file.Close()
		l.file = nil
		return err
	}

	return nil
}
